package com.wjk.kylin.rpc.core.netty.server;

import com.wjk.kylin.rpc.core.netty.codec.MessageCodecSharable;
import com.wjk.kylin.rpc.core.provider.RpcProviderFactory;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author wjk
 */
public class NettyServerChannelInitializer extends ChannelInitializer<SocketChannel> {
    private static final Logger LOGGER = LoggerFactory.getLogger(NettyServerChannelInitializer.class);

    private static final LoggingHandler LOGGING_HANDLER = new LoggingHandler(LogLevel.DEBUG);
    private static MessageCodecSharable MESSAGE_CODEC_SHARABLE = null;
    private static NettyServerHandle NETTY_SERVER_HANDLE = null;
    private static final PingMessageHandle PING_MESSAGE_HANDLE = new PingMessageHandle();

    public NettyServerChannelInitializer(RpcProviderFactory providerFactory, ThreadPoolExecutor serverHandlerPool) {
        NETTY_SERVER_HANDLE = new NettyServerHandle(providerFactory, serverHandlerPool);
        MESSAGE_CODEC_SHARABLE = new MessageCodecSharable(providerFactory.getProperties().getSerializer());
    }

    @Override
    protected void initChannel(SocketChannel channel) throws Exception {
        //处理粘包半包
        channel.pipeline().addLast(new LengthFieldBasedFrameDecoder(1024 * 1000, 4, 4, 0, 0));
        //打印日志
//        channel.pipeline().addLast(LOGGING_HANDLER);
        //编解码器
        channel.pipeline().addLast(MESSAGE_CODEC_SHARABLE);

        //关注读写事件
        channel.pipeline().addLast(new IdleStateHandler(0, 0, 60 * 3));
        //处理读写事件
        channel.pipeline().addLast(new ChannelDuplexHandler() {
            @Override
            public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
                if (evt instanceof IdleStateEvent) {
                    ctx.channel().close();      // beat 3N, close if idle
                    LOGGER.debug(">>>>>>>>>>> kylin-rpc provider netty server close an idle channel");
                } else {
                    super.userEventTriggered(ctx, evt);
                }
            }
        });
        //心跳
        channel.pipeline().addLast(PING_MESSAGE_HANDLE);

        //业务处理
        channel.pipeline().addLast(NETTY_SERVER_HANDLE);
    }

}
